﻿package ru.vega_int.firsoff.as3
{
	/**
	 * Класс занимается загрузкой в контейнер контента (изображений)
	 * Предоставляет удобные настройки  - выравнивание относительно контейнера,
	 * ресайз и т.д.
	 * Кроме этого есть система событий по началу, процессу, окончании загрузки.
	 * Скелет класса взят у К. Мука из книги по AS2 (за что ему конечно большое спасибо =) )
	 *
	 * @author firsoff maxim, email: firsoff_maxim@mail.ru, icq:235859730, tel:+79222345364
	 * @version 0.0.1 / 15.12.2007 21:22
	 */
	
	 // импорт встроенных классов
	import flash.display.Bitmap;
	import flash.display.DisplayObjectContainer;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.display.DisplayObject;
	import flash.display.Loader;		// лоадер
	import flash.display.Bitmap;
	import flash.net.URLRequest;
	import flash.display.LoaderInfo;
	import flash.events.*;
	import ru.vega_int.firsoff.as3.events.ImageViewerEvent;
	import fl.transitions.Tween;
	import fl.transitions.easing.None;
	
	// импорт собвственных классов
	//import ru.vega_int.firsoff.as3.ImageViewerEvent;
	
	public class ImageViewer extends Sprite
	{
		//// PROPERTIES
		//	private
		private var target:Sprite;			// приемник
		private var container:Sprite;		// контейнер для всего контента
		private var border:Sprite;			// спрайт носитель рамки
		private var image:Sprite;			// спрайт носитель битмапы загруженной фотки
		
		private var _url:String				// урл с которого надо грузить
		private var _width:Number;			// ширина
		private var _height:Number;			// высота
		private var _align:String;			// тип выравнивания
		private var _borderEnable:Boolean;	// нужна ли рамка
		private var borderStyle:Object;		// стиль рамки
		private const DEFAULT_BORDER_COLOR:uint = 0x000000;
		private const DEFAULT_BORDER_ALPHA:Number = 1;
		private const DEFAULT_BORDER_THICKNESS:uint = 1;
		private const DEFAULT_BORDER_INDENT:Number = 0;
		private const DEFAULT_FADE_TIME:Number = 0.5;
		
		private var _fadeEnable:Boolean;	// нужно ли всплытие из альфы
		private var _fadeTime:Number;		// время всплытия в секундах
		private var _stepFade:Number;		// шаг всплытия, рассчитывается на основе fps и времени
		private var _smooth:Boolean;		// сглаживание битмапы
		private var _resize:Boolean;		// ресайз нужен?
		private var _content:DisplayObject;		// контент
		private var _targetWidth:uint;		// ширина целевого клипа
		private var _targetHeight:uint;		// высота целевого клипа
		private var isOpen:Boolean;			//	флаг говоорит что процесс загрузки пошел
		private var _tween:Tween;			//	твинер альфы
		private var _isLoaded:Boolean = false;			//	загружена?
		private var loader:Loader;			// экземпляр лоадера
		private var urlReq:URLRequest;		//
		// 	public
		
		public var onProgress:Function;		//	функция обработчик при прогрессе
		public var id:uint;					//	Служебный идентификатор
	
		
		//// CONSTRUCTOR
		/**
		*	@param target - клип приемник
		*	@param url - ссылка
		*	@param height - высота фотки
		*	@param width - ширина фотки
		*	@param align - выравнивание
		*	@param borderEnable - нужна ли рамка
		*	@param borderStyle - стиль для обводки {thickness, color, alpha, indent}
		*	@param fadeEnable - всплытие из альфы
		*	@param fadeTime - время всплытия
		*	@param smooth - флаг сглаживания картинки BMP, false - сглаживается/ true - не сглаживается
		*	@param resize - флаг ресайза, если true - ресайза нет, если false - есть
		*/
		public function ImageViewer(target:Sprite,
								url:String,
								width:Number,
								height:Number,
								align:String,
								borderEnable:Boolean,
								borderStyle:Object,
								fadeEnable:Boolean,
								fadeTime:Number,
								smooth:Boolean,
								resize:Boolean = true)
		{
		
			this.target = target;
			this._url = url;
			this._width = width;
			this._height = height;
			this._align = align;
			this._borderEnable = borderEnable;
			this.borderStyle = borderStyle;
			this._fadeEnable = fadeEnable;
			//trace(_fadeEnable)
			this._fadeTime = Math.abs(fadeTime);
			if(!this._fadeTime){this._fadeTime = DEFAULT_FADE_TIME;};
			this._smooth = smooth;
			this._resize = resize;
			init();
		}
		
		//// METHODS
		//	private
		private function init():void
		{
			//this.mouseEnabled = true;
			loader = new Loader();				//	создаем лоадер
			loader.cacheAsBitmap = true;
			_targetWidth = target.width;
			_targetHeight = target.height;
			isOpen = false;
			//trace(_stepFade)
			createContainers();					//	создаем нужные контейнеры
			image.addChild(loader);				//	добавляем в список отображения спрайта image
			//load();							// 	загружаем изображение*/
		};
		
		/**
		* @usage Создание контейнеров (контейнер для битмапы, для рамки)
		**/
		private function createContainers():void
		{
			container = new Sprite();	// cпрайт контейнера
			image = new Sprite(); 		// создаем спрайт для изображения
			target.addChild(container);
			container.addChild(image);
			container.cacheAsBitmap = true;
			if(_borderEnable)
			{
				border = new Sprite(); 		//	создаем спрайт для рамки
				container.addChild(border);	//	добавляем к целевому клипу рамку
			};
			if(_fadeEnable)
			{
				container.alpha = 0;
			};
		};
		
		public function load():void
		{
			//trace('_url = '+_url)
			// Добавляем обработчики событий
			loader.contentLoaderInfo.addEventListener(Event.INIT, handleInit);						//	инициализация
			loader.contentLoaderInfo.addEventListener(Event.OPEN, handleOnOpen);						//	инициализация
            loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, handleIOError);		//	ошибка
			loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS , handleOnProgress);	//	прогресс
			//loader.contentLoaderInfo.addEventListener(L , handleOnProgress);	//	прогресс
			
 			urlReq = new URLRequest(_url);				//	инициализируем загрузчик
 			loader.load(urlReq);						//	---------//------------
		};
		
		/**
		* @usage  Функция обработчик инициализации загрузки
		*/
		private function handleInit(event:Event):void
		{
			//trace('handleInit')
			_isLoaded = true;
			var eventObject:Object  = new Object();
			eventObject.url = this._url;
			eventObject.target = this;
			
			//try 
			//{
				//_content = Bitmap(loader.content);
				//_content.smoothing = _smooth;
			//}
			//catch (e:Error)
			//{
				//
			//};
			
			_content = loader;
			
			//trace(_content.smoothing )
			resize();
			align();
			createBorder();
			fadeIn(container);
			var init:ImageViewerEvent = new ImageViewerEvent(ImageViewerEvent.ON_INIT, eventObject);
			this.dispatchEvent(init);
			removeEventListeners();
        };
		
		/**
		* @usage  Функция обработчик ошибок
		*/
        private function handleIOError(event:IOErrorEvent):void
		{
			trace('handleIOError - '+event.type)
			trace('this._url - '+this._url)
			var eventObject:Object  = new Object();
			eventObject.url = this._url;
			eventObject.typeError = event.type;
			eventObject.target = this;
			var init:ImageViewerEvent = new ImageViewerEvent(ImageViewerEvent.ON_ERROR, eventObject);
			this.dispatchEvent(init);
        };
		
		
		/**
		* @usage  Функция обработчик прогресса
		*/
 		private function handleOnProgress(event:ProgressEvent):void
		{
			//trace('handleOnProgress ' + event.type)
			this.dispatchEvent(event);
			if(!isOpen)
			{
				isOpen = true;
				this.dispatchEvent(new ImageViewerEvent(ImageViewerEvent.ON_OPEN));
			};
        };
		
		private function handleOnOpen(event:Event):void
		{
			/*var eventObject:Object  = new Object();
			var l:Loader = Loader(event.target);
			eventObject.bytesLoaded = l.to//event.bytesLoaded;
			eventObject.bytesTotal = //event.bytesTotal;
			//var init:ImageViewerEvent = new ImageViewerEvent(ImageViewerEvent.ON_OPEN, eventObject);
			//this.dispatchEvent(init);*/
		};
		/**
		 * Функиция делает ресайз загруженного изображения
		 */
		private function resize():void
		{
			//trace(_content.width)
			if(_resize)
			{
				var w:Number = _content.width;
				var h:Number = _content.height;
				var koeff:Number = w/h;
				var new_w:Number = _width;
				var new_h:Number = _width/koeff;
				if(new_h > _height)
				{
					new_h = _height;
					new_w = _height * koeff;
				};
				_content.width = Math.round(new_w);
				_content.height = Math.round(new_h);
			};
		};
		
		private function align():void
		{
			/*
			"T" По верхнему краю По центру
			"B" По нижнему краю По центру
			"L" По центру По левому краю
			"R" По центру По правому краю
			"TL" По верхнему краю По левому краю
			"TR" По верхнему краю По правому краю
			"BL" По нижнему краю По левому краю
			"BR" По нижнему краю По правому краю
			"C" По центру, По центру
			*/
			var x:Number = image.x;	// новые координаты контейнера
			var y:Number = image.y;
			switch(_align)
			{
				case 'T':
					x += (_targetWidth - image.width)/2;
					y = 0;
				break;
				
				case 'B':
					x += (_targetWidth - image.width)/2;
					y += _targetHeight  - image.height;
				break;
				
				case 'L':
					x += 0;
					y += (_targetHeight  - image.height)/2;
				break;
				
				case 'R':
					x += _targetWidth - image.width;
					y += (_targetHeight  - image.height)/2;
				break;
				
				case 'TL':
					x += 0;
					y += 0;
				break;
				
				case 'TR':
					x += _targetWidth - image.width;
					y += 0;
				break;
				
				case 'BL':
					x += 0;
					y += _targetHeight  - image.height;
				break;
				
				case 'BR':
					x += _targetWidth - image.width;
					y += _targetHeight  - image.height;
				break;
				
				case 'C':
					x += (_targetWidth - _content.width)/2;
					y += (_targetHeight  - _content.height)/2;
				break;
			}
			image.x = Math.round(x);
			image.y = Math.round(y);
		};
		
		/**
		 * Создает, если нужно, рамку вокруг изображения
		 */
		private function createBorder():void
		{
			if(_borderEnable)
			{
				var alpha:Number = borderStyle.alpha;
				var color:uint = borderStyle.color;
				var thickness:uint = borderStyle.thickness;
				var indent:Number = borderStyle.indent;//
				
				if(!alpha){alpha = DEFAULT_BORDER_ALPHA};
				if(!color){color = DEFAULT_BORDER_COLOR};
				if(!thickness){thickness = DEFAULT_BORDER_THICKNESS};
				if(!indent){indent = DEFAULT_BORDER_INDENT};
				
				var w:Number = image.width;
				var h:Number = image.height;
				
				border.graphics.lineStyle(thickness, color, alpha, true);
				border.graphics.moveTo(-indent, -indent);
				border.graphics.lineTo(w + indent, -indent);
				border.graphics.lineTo(w + indent, h + indent);
				border.graphics.lineTo(-indent, h + indent);
				border.graphics.lineTo(-indent, -indent);
				
				border.x = image.x;
				border.y = image.y;
			};
		};
		
		/**
		 * функция уничтожает ненужные слушатели
		 */
		private function removeEventListeners():void
		{
			try 
			{
				loader.contentLoaderInfo.removeEventListener(Event.INIT, handleInit);
				loader.contentLoaderInfo.removeEventListener(Event.OPEN, handleOnOpen);
				loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, handleIOError);			//	ошибка
				loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS , handleOnProgress);
			}
			catch (e:Error)
			{
				
			};
		};
		
		/**
		 *
		 * @param	mc	Клип для поднятия альфы
		 */
		private function fadeIn(mc:Sprite):void
		{
			_tween = new Tween(mc, 'alpha', None.easeIn, mc.alpha, 1, _fadeTime, true);
			//mc.addEventListener(Event.ENTER_FRAME, handleFadeIn);
		};
		
		private function handleFadeIn(event:Event):void
		{
			//trace(event.target.alpha)
			if(event.target.alpha < 1)
			{
				event.target.alpha += _stepFade;
			}
			else
			{
				event.target.alpha = 1;
				event.target.removeEventListener(Event.ENTER_FRAME, handleFadeIn);	//	удаляем слушателя
			};
		};
		// 	public
		
		/**
		 * Уничтожение всех листенеров и контейнеров
		 */
		public function destroy():void
		{
			removeEventListeners();
			try 
			{
				container.removeEventListener(Event.ENTER_FRAME, handleFadeIn);
				close();
				loader.unload();
				image.removeChild(loader);
				container.removeChild(image);
				loader = null;
				target.removeChild(container);
				container = null;
			}
			catch (e:Error)
			{
				
			};
			
		};
		
		public function close():void
		{
			try {loader.close();} 
			catch (error:Error) {/*trace('no loading stream');*/};
		};
		
		public function get content():Sprite
		{
			return container;
		};
		
		public function get _target():Sprite
		{
			return target;
		};
		
		public function get isLoaded():Boolean { return _isLoaded; };
	};
}